package com.fang.gateway.security.filter;

import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fang.common.common.CommonConstants;
import com.fang.common.exception.NetworkDiskException;
import com.fang.gateway.security.entity.bo.WebFluxAuthoritiesBo;
import com.fang.gateway.security.service.AuthorityService;
import com.fang.gateway.security.utils.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.web.server.context.ServerSecurityContextRepository;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;

/**
 * @Description 自定义接口请求权限过滤
 * @Author Bernie_fang
 * @Date 2025/3/9 14:18
 **/
@Slf4j
@Component
public class FluxJwtAuthenticationTokenFilter implements ServerSecurityContextRepository {

    @Resource
    private AuthorityService authorityService;

    @Override
    public Mono<Void> save(ServerWebExchange exchange, SecurityContext context) {
        return Mono.empty();
    }

    @Override
    public Mono<SecurityContext> load(ServerWebExchange exchange) {
        final String token = exchange.getRequest().getHeaders().getFirst(CommonConstants.CommonRequest.AUTHORIZATION);
        //判断当前请求中包含令牌
        if (StringUtils.isNotBlank(token)) {
            //重token中获取用户的角色权限信息
            try {
                if (!com.fang.gateway.security.utils.JWTUtil.verify(token)) {
                    log.info("verify token fail ===>");
                    return Mono.empty();
                }
                String userId = JWTUtil.getUserId(token);
                String username = JWTUtil.getUsername(token);

                Authentication newAuthentication = new UsernamePasswordAuthenticationToken(userId, username);
                return new ReactiveAuthenticationManager() {
                    @Override
                    public Mono<Authentication> authenticate(Authentication authentication) {
                        List<WebFluxAuthoritiesBo> authority = authorityService.queryUserAuthorityByUserIdForFlux(userId);
//                        ArrayList<WebFluxAuthoritiesBo> authority = new ArrayList<>();
//                        WebFluxAuthoritiesBo bo = new WebFluxAuthoritiesBo();
//                        bo.setPermissionCode("ROLE_ADMIN");
//                        authority.add(bo);
                        Authentication auth = new UsernamePasswordAuthenticationToken(userId, username, authority);
                        return Mono.just(auth);
                    }
                }.authenticate(newAuthentication).map(SecurityContextImpl::new);
            } catch (TokenExpiredException e) {
                return Mono.error(new InsufficientAuthenticationException("Token已过期", e));
            } catch (NetworkDiskException e) {
                log.error("JWTUtil 验证出错==>");
            }
        }
        return Mono.empty();
    }

}
